/*
 * Copyright (C) 2014 Sony Computer Entertainment Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#ifndef TiledBuffer_h
#define TiledBuffer_h

#include <FloatRect.h>
#include <IntPoint.h>
#include <IntPointHash.h>
#include <IntRect.h>
#include <MemcpyThread.h>
#include <cairo.h>
#include <tilebackend/tilebackend.h>
#include <wtf/Assertions.h>
#include <wtf/Atomics.h>
#include <wtf/HashMap.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>

namespace WebCore {

class TiledBuffer {
public:
    typedef WebCore::IntPoint Coordinate;
    typedef tilebackend::PoolInterface TilePool;
    typedef tilebackend::TileSize TileSize;

    ~TiledBuffer();

    void ref()
    {
        WTF::atomicIncrement(&m_refCount);
    }

    void deref()
    {
        if (!WTF::atomicDecrement(&m_refCount))
            delete this;
    }

    const tilebackend::Texture& texture() const { return m_texture; }

    Coordinate coordinate() const { return m_coordinate; }
    float contentsScale() const { return m_contentsScale; }
    void setContentsScale(float contentsScale) { m_contentsScale = contentsScale; }

    static IntRect tileRect(const IntSize&, const IntPoint& coordinate);
    static FloatRect scaledRect(const IntSize&, const IntPoint& coordinate, float scale);
    static IntRect enclosingScaledRect(const IntSize&, const IntPoint& coordinate, float scale);

    IntRect tileRect() const;
    FloatRect scaledRect() const;
    IntRect enclosingScaledRect() const;
    IntRect targetRectForPartialRepaint() const;

    IntSize tileSize() const
    {
        return IntSize(m_texture.width, m_texture.height);
    }

    static PassRefPtr<TiledBuffer> create(const Coordinate& , TilePool*);

    bool isValid() const { return m_isValid; }
    void setValid(bool isValid) { m_isValid = isValid; }

    IntRect dirtyRect() const { return m_dirtyRect; }
    void uniteDirtyRect(const IntRect& dirtyRect) { m_dirtyRect.uniteIfNonZero(dirtyRect); }
    bool isDirty() const { return !m_dirtyRect.isEmpty(); }
    void clearDirtyRect() { m_dirtyRect.setSize(IntSize()); }

    bool isReadyForPartialRepaint(float contentsScale) const
    {
        return isValid() && m_contentsScale == contentsScale && enclosingScaledRect() != m_dirtyRect;
    }

    void duplicateAsync(TiledBuffer*);
    void waitDuplicationCompleted();

protected:
    TiledBuffer() { }
    TiledBuffer(const Coordinate& , tilebackend::Texture&, TilePool*);

    volatile int m_refCount;
    Coordinate m_coordinate;
    float m_contentsScale;
    tilebackend::Texture m_texture;
    TilePool* m_pool;
    bool m_isValid;
    IntRect m_dirtyRect;

private:
    static MemcpyThread& memcpyThread();
};

} // namespace WebCore

#endif // TiledBuffer_h
